#include "ClientEntityManager.hpp"

ClientEntityManager::ClientEntityManager():EntityManager(){
	size = 1024;
    entities = new Character*[size];
	for(int i = 0; i < size; i++){
		entities[i] = 0;
	}

    Character registerent;
	registerObject(&registerent);
    
	maxPlayers = 0;
    init("Objects/c_entities.lua");
}

/** 
* Update entities in manager.
*/
void ClientEntityManager::update(unsigned int frameTime){

	//Update player 
	player->update();

	//Sync player with server
	if(player->direction & Entity::dir_Horizontal && player->moving){
		if(std::abs(player->deltaX) > player->maxVelocityX){
			if(player->deltaX < 0){
				player->x += player->maxVelocityX/5;
				player->deltaX += player->maxVelocityX/5;
			}else if(player->deltaX > 0){
				player->x -= player->maxVelocityX/5;
				player->deltaX -= player->maxVelocityX/5;
			}
		}
	}
	if(player->direction & Entity::dir_Vertical && player->moving){
		if(std::abs(player->deltaY) > player->maxVelocityY){
			if(player->deltaY < 0){
				player->y += player->maxVelocityY/5;
				player->deltaY += player->maxVelocityY/5;
			}else if(player->deltaY > 0){
				player->y -= player->maxVelocityY/5;
				player->deltaY -= player->maxVelocityY/5;
			}
		}
	}

	//Update entities
	for(int i = 0; i < size; i++){
		if(entities[i]){
            if(entities[i]->destroy){
                destroyEntity(entities[i]);
                continue;
            }
            
			runUpdate(entities[i]);

			//Sync client with expected server position.
			if(std::abs(entities[i]->deltaX) > entities[i]->maxVelocityX){
				if(entities[i]->deltaX < 0){
					entities[i]->x += entities[i]->maxVelocityX/5;
					entities[i]->deltaX += entities[i]->maxVelocityX/5;
				}else if(entities[i]->deltaX > 0){
					entities[i]->x -= entities[i]->maxVelocityX/5;
					entities[i]->deltaX -= entities[i]->maxVelocityX/5;
				}
			}
			if(std::abs(entities[i]->deltaY) > entities[i]->maxVelocityY){

				if(entities[i]->deltaY < 0){
					entities[i]->y += entities[i]->maxVelocityY/5;
					entities[i]->deltaY += entities[i]->maxVelocityY/5;
				}else if(entities[i]->deltaY > 0){
					entities[i]->y -= entities[i]->maxVelocityY/5;
					entities[i]->deltaY -= entities[i]->maxVelocityY/5;
				}
			}

			entities[i]->move();
		}
	}

	//Update player states.
    for(byte i = 0; i < maxPlayers; i++){
        if(players[i] != 0){
            players[i]->update();
			
			if(std::abs(players[i]->deltaX) > players[i]->maxVelocityX){
				if(players[i]->deltaX < 0){
					players[i]->x += players[i]->maxVelocityX/5;
					players[i]->deltaX += players[i]->maxVelocityX/5;
				}else if(players[i]->deltaX > 0){
					players[i]->x -= players[i]->maxVelocityX/5;
					players[i]->deltaX -= players[i]->maxVelocityX/5;
				}
			}
			if(std::abs(players[i]->deltaY) > players[i]->maxVelocityY){
				if(players[i]->deltaY < 0){
					players[i]->y += players[i]->maxVelocityY/5;
					players[i]->deltaY += players[i]->maxVelocityY/5;
				}else if(players[i]->deltaY > 0){
					players[i]->y -= players[i]->maxVelocityY/5;
					players[i]->deltaY -= players[i]->maxVelocityY/5;
				}
			}

        }
    }
}

/** 
* Create an entity at first available index.
*/
Entity* ClientEntityManager::createEntity(const char* name){
	for(int i = 0; i < size; i++){
		if(entities[i] == 0){
			return createEntity(name, i);
		}
	}
	return 0;
}

/** 
* Create entity at specified index.
*/
Entity* ClientEntityManager::createEntity(const char* name, uint16_t index){
	if(entities[index] == 0){
		entities[index] = new Character();
		entities[index]->index = index;
        entities[index]->init(map, 0, 0, 0);

        runStartup(entities[index], name);
        
		return entities[index];
	}
	return 0;
}

bool ClientEntityManager::destroyEntity(Entity* ent){
	if(entities[ent->index] == ent){
        if(ent->destroy == BaseObject::d_Clean){
            ent->destroy = BaseObject::d_Destroy;
        }else if(ent->destroy == BaseObject::d_Destroy){
            runDestroy(entities[ent->index]);
            //Mark for deletion on next update.
            entities[ent->index]->destroy = BaseObject::d_Delete;
        }else if(ent->destroy == BaseObject::d_Delete){
            uint16_t index = ent->index;
            delete entities[index];
            entities[index] = 0;
        }
		return true;
	}
	return false;
}


bool ClientEntityManager::destroyEntity(uint16_t index){
	if(entities[index]){
		return destroyEntity(entities[index]);
	}
	return false;
}

void ClientEntityManager::bind(lua_State* luaState){
    luabind::module(luaState)[
        luabind::class_<ClientEntityManager>("EntityManager")
			.def_readonly("size", &ClientEntityManager::size)
    ];
}

void ClientEntityManager::push(lua_State* luaState){
    luabind::object o = luabind::object(luaState, this);
    o.push(luaState);
}